home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / libkb100.zip / LIBKB-1.00 / SRC / KBMLOCK.C < prev    next >
C/C++ Source or Header  |  1996-07-23  |  11KB  |  512 lines

  1. /* kbmlock.c -- memory locking
  2.  * Copyright (C) 1995, 1996 Markus F.X.J. Oberhumer
  3.  * For conditions of distribution and use, see copyright notice in kb.h
  4.  */
  5.  
  6.  
  7. /* memory locking is currently implemented for djgpp v2 and Watcom C32 */
  8.  
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <kb.h>
  14. #include <kbmlock.h>
  15. #include "_kb.h"
  16.  
  17.  
  18. /* see also: DPMI specification
  19.  *           djgpp2/src/libc/go32/gopint.c
  20.  *           djgpp2/src/libc/dpmi/api/d0600.s
  21.  */
  22.  
  23.  
  24. #if defined(KB_LOCK_ALL_START)
  25. KB_LOCK_ALL_START(_libkb_kbmlock)
  26. #endif
  27.  
  28.  
  29. typedef struct
  30. {
  31.     int selector;
  32.     unsigned long address;
  33.     long size;
  34.     unsigned long linear_address;
  35. }
  36. kb_lockaddr_t;
  37.  
  38.  
  39.  
  40. /***********************************************************************
  41. // DPMI support for Watcom C32 (djgpp v2 compatible)
  42. ************************************************************************/
  43.  
  44. #if defined(__WATCOMC__) && defined(__KB_MSDOS32)
  45.  
  46. typedef struct
  47. {
  48.     unsigned long handle;                    /* 0, 2 */
  49.     unsigned long size;     /* or count */    /* 4, 6 */
  50.     unsigned long address;                    /* 8, 10 */
  51. } __dpmi_meminfo;
  52.  
  53.  
  54. /* it looks like every base address is 0 under DOS/4GW and PMODE/W */
  55.  
  56. /* DPMI 0.9 AX=0006 */
  57. static
  58. int __dpmi_get_segment_base_address(int _selector, unsigned long *_addr)
  59. {
  60.     KB_INT86_REGS regs;
  61.     _kb_int86_regs_init_ax(®s,0x0006);
  62.  
  63.     regs.w.bx = (unsigned short) _selector;
  64.     regs.w.flags = 0x01;                    /* be paranoid */
  65.     KB_INT86(0x31,®s);
  66.     if (regs.w.flags & 0x01)                /* error if carry flag set */
  67.         return -1;
  68.     *_addr = ((unsigned long)regs.w.cx << 16) | regs.w.dx;
  69.     return 0;
  70. }
  71.  
  72.  
  73. static
  74. int watcom_c32_do_lock(__dpmi_meminfo *_info, unsigned short ax)
  75. {
  76.     KB_INT86_REGS regs;
  77.     _kb_int86_regs_init_ax(®s,ax);
  78.  
  79.     regs.w.bx = (unsigned short) (_info->address >> 16);
  80.     regs.w.cx = (unsigned short) (_info->address);
  81.     regs.w.si = (unsigned short) (_info->size >> 16);
  82.     regs.w.di = (unsigned short) (_info->size);
  83.  
  84.     regs.w.flags = 0x01;                    /* be paranoid */
  85.     KB_INT86(0x31,®s);
  86.     return (regs.w.flags & 0x01 ? -1 : 0);    /* error if carry flag set */
  87. }
  88.  
  89. /* DPMI 0.9 AX=0600 */
  90. static
  91. int __dpmi_lock_linear_region(__dpmi_meminfo *_info)
  92. {
  93.     return watcom_c32_do_lock(_info,0x0600);
  94. }
  95.  
  96. /* DPMI 0.9 AX=0601 */
  97. static
  98. int __dpmi_unlock_linear_region(__dpmi_meminfo *_info)
  99. {
  100.     return watcom_c32_do_lock(_info,0x0601);
  101. }
  102.  
  103. #endif /* __WATCOMC__ */
  104.  
  105.  
  106. /***********************************************************************
  107. // low level locking - djgpp v2, Watcom C32
  108. ************************************************************************/
  109.  
  110. #if defined(__KB_MSDOS32)
  111. #if defined(__DJGPP__) || defined(__WATCOMC__)
  112.  
  113. #define KB_HAVE_LOCK
  114.  
  115. static int _kb_lock_lockaddr(const kb_lockaddr_t *l, int do_lock)
  116. {
  117.     int r;
  118.     __dpmi_meminfo memregion;
  119.  
  120.     memregion.handle  = 0;
  121.     memregion.address = l->linear_address;
  122.     memregion.size    = l->size;
  123.  
  124.     if (l->size <= 0)
  125.         r = -1;
  126.     else if (do_lock)
  127.         r = __dpmi_lock_linear_region(&memregion);
  128.     else
  129.         r = __dpmi_unlock_linear_region(&memregion);
  130.  
  131. #if defined(KB_DEBUG) && (KB_DEBUG >= 3)
  132.     fprintf(stderr,"libkb lockinfo: %-6s %04x:%08lx (0x%08lx), "
  133.         "%6ld bytes: %d\n", do_lock ? "lock" : "unlock",
  134.         l->selector, l->address, l->linear_address, l->size, r);
  135. #endif
  136.  
  137.     return r;
  138. }
  139.  
  140.  
  141. static
  142. int _kb_init_lockaddr(kb_lockaddr_t *l, int seg, unsigned long lockaddr,
  143.                       long locksize, int code)
  144. {
  145.     int r;
  146.  
  147.     l->selector = seg;
  148. #if defined(__DJGPP__)
  149.     if (l->selector == -1)
  150.         l->selector = code ? _go32_my_cs() : _go32_my_ds();
  151. #endif
  152.     l->address = lockaddr;
  153.     l->size = locksize;
  154.     l->linear_address = 0;
  155.  
  156.     r = __dpmi_get_segment_base_address(l->selector,&l->linear_address);
  157.     if (r == 0)
  158.         l->linear_address += l->address;
  159.     else
  160.         l->linear_address = 0;
  161.  
  162. #if defined(KB_DEBUG) && (KB_DEBUG >= 4)
  163.     fprintf(stderr,"libkb lockinfo: %-6s %04x:%08lx (0x%08lx), "
  164.         "%6ld bytes\n", "", l->selector, l->address, 
  165.         l->linear_address, l->size);
  166. #endif
  167.  
  168.     if (r != 0)
  169.         l->size = -1;
  170.     return l->size > 0 ? 0 : -1;
  171. }
  172.  
  173.  
  174. #if defined(__DJGPP__)
  175. #  define KB_INIT_LOCKADDR(l,addr,size,code) \
  176.             _kb_init_lockaddr(l,-1,(unsigned long)(addr),size,code)
  177. #elif defined(__WATCOMC__)
  178. #  define KB_INIT_LOCKADDR(l,addr,size,code) \
  179.             _kb_init_lockaddr(l,FP_SEG(addr),FP_OFF(addr),size,code)
  180. #endif
  181.  
  182.  
  183. #endif
  184. #endif /* __KB_MSDOS32 */
  185.  
  186.  
  187. /***********************************************************************
  188. // init a kb_lockaddr_t
  189. ************************************************************************/
  190.  
  191. static
  192. int _kb_init_lock_code(kb_lockaddr_t *l, void (*start)(void), void (*end)(void))
  193. {
  194.     l->size = -1;
  195.     if (start == NULL || end == NULL || start == end)
  196.         return -1;
  197.  
  198. #if defined(KB_INIT_LOCKADDR)
  199.     /* warning: ANSI C forbids ordered comparisons of pointers to functions */
  200.     {
  201.         unsigned long s = (unsigned long) start;
  202.         unsigned long e = (unsigned long) end;
  203.         if (e > s)
  204.             return KB_INIT_LOCKADDR(l,start,e-s,1);
  205.         else if (s > e)
  206.             return KB_INIT_LOCKADDR(l,end,s-e,1);
  207.         else
  208.             return -1;
  209.     }
  210. #else
  211.     l->size = 0;
  212.     return 0;
  213. #endif
  214. }
  215.  
  216.  
  217. static
  218. int _kb_init_lock_data(kb_lockaddr_t *l, const void *start, const void *end)
  219. {
  220.     l->size = -1;
  221.     if (start == NULL || end == NULL || start == end)
  222.         return -1;
  223.  
  224. #if defined(KB_INIT_LOCKADDR)
  225.     if (end > start)
  226.         return KB_INIT_LOCKADDR(l,start,(const char*)end-(const char*)start,0);
  227.     else if (start > end)
  228.         return KB_INIT_LOCKADDR(l,end,(const char*)start-(const char*)end,0);
  229.     else
  230.         return -1;
  231. #else
  232.     l->size = 0;
  233.     return 0;
  234. #endif
  235. }
  236.  
  237.  
  238. /***********************************************************************
  239. // high level locking
  240. ************************************************************************/
  241.  
  242. int kb_lock_code(void (*start)(void), void (*end)(void))
  243. {
  244.     kb_lockaddr_t l;
  245.  
  246.     if (_kb_init_lock_code(&l,start,end) != 0)
  247.         return -1;
  248. #if defined(KB_HAVE_LOCK)
  249.     return _kb_lock_lockaddr(&l,1);
  250. #else
  251.     return 0;
  252. #endif
  253. }
  254.  
  255.  
  256. int kb_lock_data(const void *start, const void *end)
  257. {
  258.     kb_lockaddr_t l;
  259.  
  260.     if (_kb_init_lock_data(&l,start,end) != 0)
  261.         return -1;
  262. #if defined(KB_HAVE_LOCK)
  263.     return _kb_lock_lockaddr(&l,1);
  264. #else
  265.     return 0;
  266. #endif
  267. }
  268.  
  269.  
  270. int kb_lock_var(const void *addr, unsigned size)
  271. {
  272.     return kb_lock_data(addr,(const char *)addr + size);
  273. }
  274.  
  275.  
  276. /***********************************************************************
  277. // high level unlocking
  278. ************************************************************************/
  279.  
  280. int kb_unlock_code(void (*start)(void), void (*end)(void))
  281. {
  282.     kb_lockaddr_t l;
  283.  
  284.     if (_kb_init_lock_code(&l,start,end) != 0)
  285.         return -1;
  286. #if defined(KB_HAVE_LOCK)
  287.     return _kb_lock_lockaddr(&l,0);
  288. #else
  289.     return 0;
  290. #endif
  291. }
  292.  
  293.  
  294. int kb_unlock_data(const void *start, const void *end)
  295. {
  296.     kb_lockaddr_t l;
  297.  
  298.     if (_kb_init_lock_data(&l,start,end) != 0)
  299.         return -1;
  300. #if defined(KB_HAVE_LOCK)
  301.     return _kb_lock_lockaddr(&l,0);
  302. #else
  303.     return 0;
  304. #endif
  305. }
  306.  
  307.  
  308. int kb_unlock_var(const void *addr, unsigned size)
  309. {
  310.     return kb_unlock_data(addr,(const char *)addr + size);
  311. }
  312.  
  313.  
  314. /***********************************************************************
  315. // merge overlapping regions
  316. //
  317. // We try to lock as few different regions as possible.
  318. ************************************************************************/
  319.  
  320. #if defined(KB_HAVE_LOCK)
  321.  
  322. static int _kb_merge2(kb_lockaddr_t *l1, kb_lockaddr_t *l2)
  323. {
  324.     unsigned long end1, end2;
  325.  
  326.     if (l1->size <= 0 || l2->size <= 0)
  327.         return 0;
  328.  
  329.     end1 = l1->linear_address + l1->size;
  330.     end2 = l2->linear_address + l2->size;
  331.  
  332.     /* try to merge l2 into l1 */
  333.     if (l1->linear_address <= l2->linear_address &&
  334.         end1 + 1 >= l2->linear_address)
  335.     {
  336.         if (end2 > end1)
  337.             l1->size = end2 - l1->linear_address;
  338.         l2->size = 0;
  339.         return 1;
  340.     }
  341.  
  342.     /* try to merge l1 into l2 */
  343.     if (l2->linear_address <= l1->linear_address &&
  344.         end2 + 1 >= l1->linear_address)
  345.     {
  346.         if (end1 > end2)
  347.             l2->size = end1 - l2->linear_address;
  348.         l1->size = 0;
  349.         return 1;
  350.     }
  351.  
  352.     return 0;
  353. }
  354.  
  355.  
  356. static
  357. int _kb_merge_lockaddr(kb_lockaddr_t l[], int n)
  358. {
  359.     int i, j;
  360.     int found;
  361.  
  362.     /* a simple 'bubblemerge' (like bubblesort) */
  363.  
  364.     do {
  365.         found = 0;
  366.  
  367.         for (i = 0; i < n - 1; i++)
  368.             for (j = i + 1; j < n; j++)
  369.                 if (_kb_merge2(&l[i],&l[j]))
  370.                     found = 1;
  371.  
  372.     } while (found);
  373.  
  374.     return 0;
  375. }
  376.  
  377.  
  378. #if defined(KB_DEBUG) && (KB_DEBUG >= 4)
  379. static
  380. void _kb_print_lockaddr(const kb_lockaddr_t ll[], int n, const char *s)
  381. {
  382.